package com.baidu.service;

import com.baidu.entity.*;
import com.baidu.mapper.*;
import com.baidu.utils.DateUtil;
import com.baidu.utils.ResultResponse;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

@Service
@Transactional
@Slf4j
public class LoansServiceImpl implements LoansService{
    //产品
    @Resource
    private ProductMapper pmapper;
    //期数
    @Resource
    private NumbersMapper nmapper;
    //利率
    @Resource
    private InterestMapper imapper;
    //还款方式
    @Resource
    private MorMapper morMapper;
    //借款记录
    @Resource
    private BorrMapper bmapper;
    //预还款计划表
    @Resource
    private SkedMapper smapper;
    //redis
    @Resource
    private RedisUtils redisUtils;
    //借款表
    @Resource
    private BorrMapper borrMapper;
    /**
     * 预还款记录
     * @param borr 产品pid，期数的nid,和借款金额prices
     * @return ResultResponse
     */
    @Override
    public synchronized ResultResponse preview (Borr borr) {
        if (borr.getPid() == null) {
            return ResultResponse.FAILED("请选择产品");
        }
        //查询产品，根据产品查看利率，还款方式
        HashMap map = this.selectone(borr.getPid());
        Product product = (Product) map.get("product");
        if (product == null||product.getStatus()!=1) {
            return ResultResponse.FAILED("选择正确的产品");
        }
        //查询期数
        QueryWrapper<Numbers> queryWrapperss = new QueryWrapper<>();
        queryWrapperss.eq("nid", borr.getNid());
        Numbers numbers = nmapper.selectOne(queryWrapperss);
        Mor mor = (Mor) map.get("mor");
        Interest interest = (Interest) map.get("interest");
        //总金额
        long a = borr.getPrices();
        //期数
        Integer z = numbers.getNums();
        //记录
        double s = 0;
        Double monthr = interest.getMonthr();
        ArrayList<Sked> list = new ArrayList<>();
        //等本等息：
        //借款金额：z
        //月息：日利率*30
        //贷款期数：n
        //每月还款本金：z/n（约到分最后一次还款本金应是所有期数加在一起为贷款总金额）
        //每月还款利息：z*月息%
        //每月还款金额：本金+利息
        if (mor.getMid() == 3) {
            //月利率
            for (int i = 0; i < z; i++) {
                Sked sked = new Sked();
                sked.setWvs(i + 1);
                double v = (a - s) * monthr * 0.01;
                //利息
                sked.setInterest(v);
                long t = a / z;
                double h = (double) t;
                //本金
                sked.setPrincipal(h);
                //总计
                sked.setNums(v + h);
                if (i == z - 1) {
                    sked.setPrincipal(a - s);
                    sked.setNums(a - s + v);
                }
                s = s + h;
                list.add(sked);
            }
            return ResultResponse.SUCCESS(list);
        }
        //等额本金：
        //借款金额：z
        //月息：日利率*30
        //贷款期数：n
        //每月还款本金：z/n（约到分最后一次还款本金应是所有期数加在一起为贷款总金额）
        //每月还款利息为：（z-已还本金）*月息%
        //每月应还：本金加利息
        if (mor.getMid() == 2) {
            for (int i = 0; i < z; i++) {
                Sked sked = new Sked();
                sked.setWvs(i + 1);
                double v = borr.getPrices() * monthr * 0.01;
                sked.setInterest(v);
                long t = a / z;
                double h = (double) t;
                //本金
                sked.setPrincipal(h);
                //总计
                sked.setNums(v + h);
                if (i == z - 1) {
                    sked.setPrincipal(a - s);
                    sked.setNums(a - s + v);
                }
                s = s + h;
                list.add(sked);
            }
            return ResultResponse.SUCCESS(list);
        }
        //等额本息 a本金 monthr 月利率  z月数
        //〔贷款本金×月利率×(1+月利率)^还款月数 〕÷〔(1+月利率)^还款月数-1〕
        //每月应还利息=剩余本金*月利率
        //月还款利息：第一期应还利息=10000*1%=100 ；
        //月还款本金：PMT-每月还款利息Math.pow(v, t)
        /**★★★（double丢失精度问题）
         * 这里涉及到了double丢失精度的问题，因为涉及金额的计算都必须十分精确
         * 所以丢失精度的问题必须解决
         * 我就使用了BigDecimal（用来对超过16位有效位的数进行精确的运算）
         * 从而解决了double丢失精度的问题
         */
        BigDecimal ab = new BigDecimal(a);
        BigDecimal mb = new BigDecimal(monthr*12* 0.01);
        if (mor.getMid() == 1) {
            ArrayList list1 = Dengx.calculate(ab, mb, z);
            return ResultResponse.SUCCESS(list1);
        }

        return ResultResponse.FAILED("请选择重新选择，选择不正确，或刷新重试");
    }

    /**
     * 用户点击借款
     * @param borr 用户id，是否同意协议产品pid，期数nid，借款金额prices
     * @return ResultResponse
     */
    @Override
    public synchronized ResultResponse borrow (Borr borr) {
        if(borr.getDeal()!=1){
            return ResultResponse.FAILED("请阅读协议，同意并签署");
        }
        if(borr.getUserid()!=null&&borr.getUserid()==0){
            return ResultResponse.FAILED("请登录");
        }
        //查询基本信息是否都已经填写；
        ResultResponse cha = this.cha(borr);
        if(cha.getCode()==-1){
            return cha;
        }
        //查看信用积分是否足够，需要调用微服务暂未开发完成
        //生成借款记录
        //时间
        borr.setTimes(DateUtil.dang());
        //是否打款1/0
        borr.setRemit(0);
        bmapper.insert(borr);
        ResultResponse preview = this.preview(borr);
        ArrayList<Sked> data = (ArrayList<Sked>) preview.getData();
        int i=0;
        for (Sked datum : data) {
            i=i+1;
            datum.setWon(0);
            datum.setBid(borr.getBid());
            Date date = DateUtil.stepMonth(borr.getTimes(), i);
            datum.setTimes(date);
            smapper.insert(datum);
            log.info("用户：{},借款记录：{}",borr.getUserid(),datum);
        }
        //调用支付打款并更改记录，需要调用，尚未开发
        //调用扣除对应的信用积分，需要调用，尚未开发
        //扣除公司账户金额,需要调用，尚未开发
        return ResultResponse.SUCCESS("借款成功,借款金额会在1到2天内打到银行账户");
    }

    /**
     * 查询各种列表通过map形式返回
     * @return ResultResponse
     */
    @Override
    public ResultResponse particulars () {
        HashMap<String, List> map = new HashMap<>();
        //查询所有还款方式
        List<Mor> mors = morMapper.selectList(null);
        map.put("mors",mors);
        //查询所有利息
        List<Interest> interests = imapper.selectList(null);
        map.put("interests",interests);
        return ResultResponse.SUCCESS(map);
    }

    /**
     * 查询审核通过的列表
     * @return ResultResponse
     */
    @Override
    public ResultResponse product () {
        QueryWrapper<Product> wrapper = new QueryWrapper<>();
        wrapper.eq("status", 1);
        List<Product> products = pmapper.selectList(wrapper);
        return ResultResponse.SUCCESS(products);
    }



    private ResultResponse cha(Borr borr){
        if (borr.getPid() == null) {
            return ResultResponse.FAILED("请选择产品");
        }
        //查询产品，根据产品查看利率，还款方式
        HashMap map = this.selectone(borr.getPid());
        Product product = (Product) map.get("product");
        //产品是否存在和是否审核通过
        if (product == null||product.getStatus()!=1) {
            return ResultResponse.FAILED("选择正确的产品");
        }
        //查询期数
        QueryWrapper<Numbers> queryWrapperss = new QueryWrapper<>();
        queryWrapperss.eq("nid", borr.getNid());
        Numbers numbers = nmapper.selectOne(queryWrapperss);
        if(numbers==null){
            return ResultResponse.FAILED("请选择正确的期数");
        }
        return ResultResponse.SUCCESS(map);
    }

    /**
     * 查询一条数据信息
     */
    private HashMap selectone (Integer pid) {
        HashMap<String, Object> map = new HashMap<>();
        //查询产品
        QueryWrapper<Product> wrapper = new QueryWrapper<>();
        wrapper.eq("pid", pid);
        Product product = pmapper.selectOne(wrapper);
        map.put("product", product);
        //查询还款方式
        QueryWrapper<Mor> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("mid", product.getMid());
        Mor mor = morMapper.selectOne(queryWrapper);
        map.put("mor", mor);
        //查询利率
        QueryWrapper<Interest> queryWrappers = new QueryWrapper<>();
        queryWrappers.eq("rid", product.getRid());
        Interest interest = imapper.selectOne(queryWrappers);
        map.put("interest", interest);
        return map;
    }

    /**
     * 定时同步公司收益
     */
    /**
//    @Scheduled(cron="0 0 0 * * ?")   //每天凌晨零点执行一次
//    @Scheduled(cron="0/30 * * * * *")
    public void quartzPublish() {
        this.zhi();
    }
    public void zhi(){
        //分组查询并返回对应的合计值
        QueryWrapper<Sked> wrapper = new QueryWrapper<>();
        wrapper.select("won","SUM(interest) as interest")
                .groupBy("won");
        //1已还/0未还
        List<Sked> skeds = smapper.selectList(wrapper);
        for (Sked sked : skeds) {
            if(sked.getWon()==1){
                redisUtils.set("practical",sked.getInterest());
                log.info("公司实际收益为：{}",sked.getInterest());
            }
            if(sked.getWon()==0){
                redisUtils.set("future",sked.getInterest());
                log.info("公司未来收益为：{}",sked.getInterest());
            }
        }
    }
     */
    /**
     * 增量查询公司收益
     */
//    @Scheduled(cron="0 0 0 * * ?")   //每天凌晨零点执行一次
    @Scheduled(cron="0/30 * * * * *")
    public void saveQuartzPublish() {
        this.pan();
    }
    public void pan(){
        Double practical = (Double) redisUtils.get("practical");
        Double future = (Double) redisUtils.get("future");
        log.info("当前收益为：{}",practical);
        log.info("未来收益为：{}",future);
        Date date = new Date();
        Date date1 = DateUtil.rollDay(date, -1);
        //这里有一个时间精度的问题
        /**★★★（不常见问题）
         * 因为我上面的date类型在和数据库中的date类型的转换过程中，
         * 由date类型转换成了datetime类型，导致时分秒成为了00:00：00
         * 所以就需要我下一步的操作，时间精度的转换
         * 如果不进行转换，以下的查询就会为空，
         * 导致我所写的收益增量不执行，结果错误
         */
        Date date2 = DateUtil.toDayStartHour(date1);
        QueryWrapper<Borr> wrapper = new QueryWrapper<>();
        QueryWrapper<Borr> times = wrapper.eq("times", date2);
        List<Borr> borrs = borrMapper.selectList(times);
        if (borrs!=null){
            for (Borr borr : borrs) {
                Integer bid = borr.getBid();
                QueryWrapper<Sked> wrapper1 = new QueryWrapper<>();
                QueryWrapper<Sked> bid1 = wrapper1.eq("bid", bid);
                List<Sked> skeds = smapper.selectList(bid1);
                for (Sked sked : skeds) {
                    if(sked.getWon()==1){
                        practical=practical+sked.getInterest();
                    }
                    if(sked.getWon()==0){
                        future= future+sked.getInterest();
                    }
                }
                redisUtils.set("practical",practical);
                log.info("公司实际收益为：{}",practical);
                redisUtils.set("future",future);
                log.info("公司未来收益为：{}",future);
            }
        }else {
            redisUtils.set("practical",practical);
            log.info("公司实际收益为：{}",practical);
            redisUtils.set("future",future);
            log.info("公司未来收益为：{}",future);
        }
    }


    /**
     * 查看各种收益
     * @return ResultResponse
     */
    @Override
    public ResultResponse proa(){
        //取出值
        Double practical = (Double) redisUtils.get("practical");
        Double future = (Double) redisUtils.get("future");
        redisUtils.set("summation",practical+future);
        log.info("收益总计：{}",practical+future);
        HashMap<String, Double> map = new HashMap<>();
        map.put("practical",practical);
        map.put("future",future);
        map.put("summation",practical+future);
        return ResultResponse.SUCCESS(map);
    }
    @Override
    public ResultResponse over (Borr borr) {
        if(borr.getUserid()==null){
            return ResultResponse.FAILED("请登录");
        }
        log.info("用户{}查看还款记录",borr.getUserid());
        QueryWrapper<Borr> wrapper = new QueryWrapper<>();
        wrapper.eq("userid",borr.getUserid())
                .eq("emptys",0);
        List<Borr> borrs = bmapper.selectList(wrapper);
        if(borrs==null){
            return ResultResponse.SUCCESS("暂无未还完的借款记录");
        }
        return ResultResponse.SUCCESS(borrs);
    }

    @Override
    public ResultResponse onesr (Borr borr) {
        if(borr.getUserid()==null){
            return ResultResponse.FAILED("请登录");
        }
        if(borr.getBid()==null){
            return ResultResponse.FAILED("请选择正确的记录");
        }
        log.info("用户{}，查看{}还款详细计划",borr.getUserid(),borr.getBid());
        QueryWrapper<Sked> wrapper = new QueryWrapper<>();
        wrapper.eq("bid",borr.getBid());
        List<Sked> skeds = smapper.selectList(wrapper);
        if(skeds==null){
            log.info("{}该条记录不存在",borr.getBid());
            return ResultResponse.FAILED("不存在该记录");
        }
        return ResultResponse.SUCCESS(skeds);
    }
}
